package Hxw3DEngine.core.materials
{
	import Hxw3DEngine.asset.parsers.A3DObjParser;
	import Hxw3DEngine.core.Resource.geometry.ResourceGeometry;
	import Hxw3DEngine.core.Resource.texture.ResourceTexture;
	import Hxw3DEngine.core.component.Transform3D;
	import Hxw3DEngine.core.controller.Camera3D;
	import Hxw3DEngine.core.display.GameObject;
	import Hxw3DEngine.core.materials.shader.Shader3D;
	import Hxw3DEngine.error.OverrideError;
	import Hxw3DEngine.proxy.Stage3DProxy;
	
	import flash.display3D.Context3D;
	import flash.display3D.Context3DBlendFactor;
	import flash.display3D.Context3DTriangleFace;
	import flash.geom.Matrix3D;
	import flash.media.Camera;
	
	public class Material3D
	{
		
		
		public static const BLEND_NONE 			: String = 'BLEND_NONE';
		public static const BLEND_ADDITIVE 		: String = 'BLEND_ADDITIVE';
		public static const BLEND_ALPHA_BLENDED : String = 'BLEND_ALPHA_BLENDED';
		public static const BLEND_MULTIPLY 		: String = 'BLEND_MULTIPLY';
		public static const BLEND_SCREEN 		: String = 'BLEND_SCREEN';
		public static const BLEND_ALPHA 		: String = 'BLEND_ALPHA';
		
		protected var _sourceFactor	: String;								// 混合模式
		protected var _destFactor	: String;								// 混合模式
		protected var _depthWrite 	: Boolean;								// 开启深度
		protected var _depthCompare : String;								// 测试条件
		protected var _cullFace 	: String;								// 裁剪
		protected var _blendMode 	: String = BLEND_NONE;					// 混合模式
		protected var _stateDirty	: Boolean = false;						// context状态
		
		
		
		public function Material3D(_shader:Shader3D = null):void{
			shader = _shader;
			this._stateDirty	= false;
			this._depthWrite  	= Stage3DProxy.defaultDepthWrite;
			this._depthCompare	= Stage3DProxy.defaultCompare;
			this._cullFace	 	= Stage3DProxy.defaultCullFace;
			this._sourceFactor	= Stage3DProxy.defaultSourceFactor;
			this._destFactor	= Stage3DProxy.defaultDestFactor;
		}
		
		private var _shader:Shader3D;
		
		public function get shader():Shader3D {
			return _shader;
		}
		
		public function set shader(value:Shader3D):void {
			_shader = value;
		}
		
		
		private var _shaderList:Vector.<Shader3D>;
		
		public function get shaderList():Vector.<Shader3D>{
			return _shaderList ||= new Vector.<Shader3D>();
		}
		
		
		public function addShader(shader:Shader3D):void{
			_shaderList.push(shader);
			
		}
		
		public function draw(geometry:ResourceGeometry, context:Context3D):void {
			// 修改混合、深度测试、裁减
			if (_stateDirty) {
				context.setBlendFactors(sourceFactor, destFactor);
				context.setDepthTest(depthWrite, depthCompare);
				context.setCulling(cullFace);
			}
			
			shader.draw(geometry, context);
			
			// 重置回默认状态
			if (_stateDirty) {
				context.setBlendFactors(Stage3DProxy.defaultSourceFactor, Stage3DProxy.defaultDestFactor);
				context.setDepthTest(Stage3DProxy.defaultDepthWrite, Stage3DProxy.defaultCompare);
				context.setCulling(Stage3DProxy.defaultCullFace);
			}
		}
		
		/** 裁剪 */
		public function get cullFace() : String {
			return _cullFace;
		}
		
		/**
		 * @private
		 */
		public function set cullFace(value:String):void {
			_cullFace = value;
			this.validateState();
		}
		
		/** 深度测试条件 */
		public function get depthCompare():String {
			return _depthCompare;
		}
		
		/**
		 * @private
		 */
		public function set depthCompare(value:String):void {
			_depthCompare = value;
			this.validateState();
		}
		
		/** 深度测试 */
		public function get depthWrite():Boolean {
			return _depthWrite;
		}
		
		/**
		 * @private
		 */
		public function set depthWrite(value:Boolean):void {
			_depthWrite = value;
			this.validateState();
		}
		
		/** 混合模式->destFactor */
		public function get destFactor():String {
			return _destFactor;
		}
		
		/**
		 * @private
		 */
		public function set destFactor(value:String):void {
			_destFactor = value;
			this.validateState();
		}
		
		/** 混合模式->sourceFactor */
		public function get sourceFactor():String {
			return _sourceFactor;
		}
		
		/**
		 * @private
		 */
		public function set sourceFactor(value:String):void {
			_sourceFactor = value;
			this.validateState();
		}
		
		/**
		 * 透明 
		 * @return 
		 */		
		public function get transparent() : Boolean {
			return blendMode == BLEND_ALPHA ? true : false;
		}
		
		/**
		 * 透明 
		 * @param value
		 */		
		public function set transparent(value : Boolean) : void {
			if (value) {
				this.blendMode = BLEND_ALPHA;
			} else {
				this.blendMode = BLEND_NONE;
			}
		}
		
		/**
		 * 双面显示 
		 * @return 
		 */		
		public function get twoSided() : Boolean {
			return this.cullFace == Context3DTriangleFace.NONE;
		}
		
		/**
		 * 双面显示
		 * @param value
		 */
		public function set twoSided(value : Boolean) : void {
			if (value) {
				this.cullFace = Context3DTriangleFace.NONE;
			} else {
				this.cullFace = Context3DTriangleFace.BACK;
			}
			this.validateState();
		}
		
		/**
		 * 混合模式 
		 * @return 
		 * 
		 */		
		public function get blendMode() : String {
			return this._blendMode;
		}
		
		/**
		 * 设置混合模式
		 * @param value
		 */
		public function set blendMode(value : String) : void {
			if (_blendMode == value) {
				return;
			}
			this._blendMode = value;
			switch (this._blendMode) {
				case BLEND_NONE:
					this.sourceFactor 	= Context3DBlendFactor.ONE;
					this.destFactor 	= Context3DBlendFactor.ZERO;
					break;
				case BLEND_ADDITIVE:
					this.sourceFactor 	= Context3DBlendFactor.ONE;
					this.destFactor 	= Context3DBlendFactor.ONE;
					break;
				case BLEND_ALPHA_BLENDED:
					this.sourceFactor 	= Context3DBlendFactor.ONE;
					this.destFactor 	= Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
					break;
				case BLEND_MULTIPLY:
					this.sourceFactor 	= Context3DBlendFactor.DESTINATION_COLOR;
					this.destFactor 	= Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
					break;
				case BLEND_SCREEN:
					this.sourceFactor 	= Context3DBlendFactor.ONE;
					this.destFactor 	= Context3DBlendFactor.ONE_MINUS_SOURCE_COLOR;
					break;
				case BLEND_ALPHA:
					this.sourceFactor 	= Context3DBlendFactor.SOURCE_ALPHA;
					this.destFactor 	= Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
					break;
			}
			this.validateState();
		}
		
		private function validateState() : void {
			this._stateDirty = true;
			if (this.sourceFactor 	== Stage3DProxy.defaultSourceFactor &&
				this.destFactor		== Stage3DProxy.defaultDestFactor	&&
				this.depthCompare	== Stage3DProxy.defaultCompare		&&
				this.depthWrite		== Stage3DProxy.defaultDepthWrite	&&
				this.cullFace		== Stage3DProxy.defaultCullFace) {
				this._stateDirty = false;
			}
		}
		
		
		
	}
}